/*
 * UdtUdtSocketPair.cpp
 *
 *  Created on: 2016年6月24日
 *      Author: terry
 */

#include "BasicType.h"
#include "UdtSocketPair.h"

#ifdef WIN32
#include <Ws2tcpip.h>
#endif //

#include <evutil.h>

namespace util
{

UdtSocketPair::UdtSocketPair():
	m_listen(UDT::INVALID_SOCK),
	m_serverSocket(UDT::INVALID_SOCK),
	m_clientSocket(UDT::INVALID_SOCK)
{
}

UdtSocketPair::~UdtSocketPair()
{
	close();
}


bool UdtSocketPair::open()
{
	m_listen = UDT::socket(AF_INET, SOCK_STREAM, 0);
	if (m_listen == UDT::INVALID_SOCK)
	{
		return false;
	}

	sockaddr_in my_addr;
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(0);
	//my_addr.sin_addr.s_addr = INADDR_ANY;

#if defined(_MSC_VER)
	evutil_inet_pton(AF_INET, "127.0.0.1", &my_addr.sin_addr);
#else
	inet_pton(AF_INET, "127.0.0.1", &my_addr.sin_addr);
#endif

	memset(&(my_addr.sin_zero), '\0', 8);

	UDT::bind(m_listen, (sockaddr *)&my_addr, sizeof(my_addr));
	UDT::listen(m_listen, 2);

    bool done = makeConnection(m_listen, my_addr);

    //UDT::close(m_listen);
    //m_listen = UDT::INVALID_SOCK;

    return done;
}

void UdtSocketPair::close()
{
	if (m_clientSocket != UDT::INVALID_SOCK)
	{
		UDT::close(m_clientSocket);
		m_clientSocket = UDT::INVALID_SOCK;
	}

	if (m_serverSocket != UDT::INVALID_SOCK)
	{
		UDT::close(m_serverSocket);
		m_serverSocket = UDT::INVALID_SOCK;
	}

	if (m_listen != UDT::INVALID_SOCK)
	{
		UDT::close(m_listen);
		m_listen = UDT::INVALID_SOCK;
	}

}

UDTSOCKET UdtSocketPair::getPeerHandle() const
{
    return m_serverSocket;
}

UDTSOCKET UdtSocketPair::getHandle() const
{
    return m_clientSocket;
}

void UdtSocketPair::makeReadable()
{
    int byte = 0x99;
    UDT::send(m_serverSocket, (char*)&byte, sizeof(int), 0);
}

void UdtSocketPair::clearReadable()
{
    const int BUFFER_MAX = 100;
    char buffer[BUFFER_MAX] = {0};
    int ret = UDT::recv(m_clientSocket, buffer, sizeof(buffer), 0);
    while (ret == BUFFER_MAX)
    {
        ret = UDT::recv(m_clientSocket, buffer, sizeof(buffer), 0);
    }
}

bool UdtSocketPair::makeConnection(UDTSOCKET& listenSocket, sockaddr_in& addr)
{
    m_clientSocket = UDT::socket(AF_INET, SOCK_STREAM, 0);
    
    bool recvSync = false;
    UDT::setsockopt(m_clientSocket, 0, UDT_RCVSYN, &recvSync, sizeof(recvSync));

    int ret = UDT::connect(m_clientSocket, (sockaddr*)&addr, sizeof(addr));

    m_serverSocket = UDT::accept(listenSocket, NULL, 0);

    if (m_serverSocket == UDT::INVALID_SOCK)
    {
    	UDT::close(m_clientSocket);
    	m_clientSocket = UDT::INVALID_SOCK;
    	return false;
    }

    return true;
}




} /* namespace util */
